<?php
namespace common\models;

use Yii;
use yii\behaviors\TimestampBehavior;
use yii\base\Exception;

/**
 * This is the model class for table "game_types".
 *
 * @property integer $type_id
 * @property string $type_name
 * @property integer $type_fid
 * @property string $game_count
 * @property string $alias
 * @property string $pic
 */
class GameType extends \yii\db\ActiveRecord
{

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'game_types';
    }

    /**
     * 产生创建日期和更新日期时间戳
     */
    public function behaviors()
    {
        return [
            [
                'class' => TimestampBehavior::className(),
                'createdAtAttribute' => 'created_at',
                'updatedAtAttribute' => 'updated_at'
            ]
        ];
    }

    /**
     * 更新前，更新所有的子级路径
     */
    public function beforeSave($insert = false)
    {
        // 如果修改了 parent_path 属性，同步更改所有子模型的 parent_path 。
        if ($this->isAttributeChanged('parent_path')) {
            // 防止树循环。阻止将当前分类放到子分类下。
            $primary_key = static::primaryKey();
            $primary_key = $primary_key[0];
            if (! empty($this->parent_path)) {
                $parent_node = $this->parentNode()->one();
                if (! is_object($parent_node) || preg_match('/:' . $this->{$primary_key} . ':/', $parent_node->parent_path)) {
                    throw new Exception('所属父级不能为空，且其新的父级不能为其原来的子级！');
                    return false;
                }
            }
            $old_path = (is_null($this->getOldAttribute('parent_path')) ? ':' : $this->getOldAttribute('parent_path')) . $this->{$primary_key} . ':';
            // 为了性能，不使用递归，直接操作数据表。
            Yii::$app->db->createCommand('UPDATE `' . $this->tableName() . '` SET `parent_path` = CONCAT(\'' . $this->path . '\', substring(`parent_path`, ' . (strlen($old_path) + 1) . ')) WHERE `parent_path` LIKE \'' . $old_path . '%\'')
                ->execute();
        }
        parent::beforeSave(true);
        return true;
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [
                [
                    'type_name',
                    'alias'
                ],
                'required'
            ],
            [
                [
                    'type_name',
                    'alias'
                ],
                'unique'
            ],
            [
                [
                    'parent_id',
                    'game_count'
                ],
                'integer'
            ],
            [
                [
                    'type_name'
                ],
                'string',
                'max' => 100
            ],
            [
                [
                    'alias'
                ],
                'string',
                'max' => 50
            ],
            [
                [
                    'pic'
                ],
                'string',
                'max' => 200
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'type_id' => '类型ID',
            'parent_id' => '父级类型ID',
            'type_name' => '类型名称',
            'parent_path' => '上级路径',
            'path' => '当前路径',
            'game_count' => '游戏数量',
            'alias' => '类型别名',
            'pic' => '类型图片',
            'created_at' => 'Created At',
            'updated_at' => 'Updated At'
        ];
    }

    // relationship
    /**
     * 对应的游戏[一个游戏类型可有多个游戏]
     */
    public function getGames()
    {
        return $this->hasMany(Game::className(), [
            'game_id' => 'game_id'
        ])->viaTable('game_with_type', [
            'type_id' => 'type_id'
        ]);
    }

    /**
     * 上级游戏类型模型ID[注意：框架不支持自动识别驼峰命名，否则属性就会变成parentId]
     */
    public function getParent_id()
    {
        if (! isset($this->attributes['parent_path'])) {
            return null;
        }
        $arr = explode(':', trim($this->attributes['parent_path'], ':'));
        return (int) end($arr);
    }

    /**
     * 当前模型路径
     */
    public function getPath()
    {
        $primary_key = static::primaryKey();
        return ($this->attributes['parent_path'] ?  : ':') . $this->attributes[$primary_key[0]] . ':';
    }

    /**
     * 设置父模型ID的时候，并修正 parent_path 属性。
     */
    public function setParent_id($value)
    {
        $parent = $value ? static::findOne($value) : null;
        $this->setAttribute('parent_path', is_object($parent) ? $parent->path : '');
    }

    /**
     * 顶级节点
     */
    public static function topNode()
    {
        return static::find()->where('parent_path=:parent_path')->addParams([
            ':parent_path' => ''
        ]);
    }

    /**
     * 父节点
     */
    public function parentNode()
    {
        return static::find()->where('type_id=:type_id')->addParams([
            ':type_id' => $this->parent_id
        ]);
    }

    /**
     * 子节点，仅下一级
     */
    public function childNode()
    {
        return static::find()->where('parent_path=:parent_path')->addParams([
            ':parent_path' => $this->path
        ]);
    }

    /**
     * 所有子节点，包括子节点的子节点
     *
     * @param boolean $self
     *            是否包含自己，默认不包含。
     */
    public function childNodes($self = false)
    {
        $primary_key = static::primaryKey();
        $query = static::find()->where("parent_path like '" . $this->path . "%'");
        if ($self) {
            $query->orWhere("{$primary_key[0]}={$this->attributes[$primary_key[0]]}");
        }
        return $query;
    }
}
